{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Multiclass Voting Classifier to Predict Wine Quality Score\n",
    "\n",
    "## Wine Data\n",
    "Data from http://archive.ics.uci.edu/ml/datasets/Wine+Quality\n",
    "\n",
    "### Citations\n",
    "P. Cortez, A. Cerdeira, F. Almeida, T. Matos and J. Reis. \n",
    "Modeling wine preferences by data mining from physicochemical properties.\n",
    "In Decision Support Systems, Elsevier, 47(4):547-553. ISSN: 0167-9236.\n",
    "\n",
    "Available at:\n",
    "- [@Elsevier](http://dx.doi.org/10.1016/j.dss.2009.05.016)\n",
    "- [Pre-press (pdf)](http://www3.dsi.uminho.pt/pcortez/winequality09.pdf)\n",
    "- [bib](http://www3.dsi.uminho.pt/pcortez/dss09.bib)\n",
    "\n",
    "Dua, D. and Karra Taniskidou, E. (2017). UCI Machine Learning Repository [http://archive.ics.uci.edu/ml]. Irvine, CA: University of California, School of Information and Computer Science.\n",
    "## Setup"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib inline\n",
    "\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "import seaborn as sns\n",
    "\n",
    "red_wine = pd.read_csv('../../ch_10/data/winequality-red.csv')\n",
    "white_wine = pd.read_csv('../../ch_10/data/winequality-white.csv', sep=';')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## EDA"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>fixed acidity</th>\n",
       "      <th>volatile acidity</th>\n",
       "      <th>citric acid</th>\n",
       "      <th>residual sugar</th>\n",
       "      <th>chlorides</th>\n",
       "      <th>free sulfur dioxide</th>\n",
       "      <th>total sulfur dioxide</th>\n",
       "      <th>density</th>\n",
       "      <th>pH</th>\n",
       "      <th>sulphates</th>\n",
       "      <th>alcohol</th>\n",
       "      <th>quality</th>\n",
       "      <th>kind</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>848</th>\n",
       "      <td>6.4</td>\n",
       "      <td>0.64</td>\n",
       "      <td>0.21</td>\n",
       "      <td>1.8</td>\n",
       "      <td>0.081</td>\n",
       "      <td>14.0</td>\n",
       "      <td>31.0</td>\n",
       "      <td>0.99689</td>\n",
       "      <td>3.59</td>\n",
       "      <td>0.66</td>\n",
       "      <td>9.8</td>\n",
       "      <td>5</td>\n",
       "      <td>red</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2529</th>\n",
       "      <td>6.6</td>\n",
       "      <td>0.42</td>\n",
       "      <td>0.13</td>\n",
       "      <td>12.8</td>\n",
       "      <td>0.044</td>\n",
       "      <td>26.0</td>\n",
       "      <td>158.0</td>\n",
       "      <td>0.99772</td>\n",
       "      <td>3.24</td>\n",
       "      <td>0.47</td>\n",
       "      <td>9.0</td>\n",
       "      <td>5</td>\n",
       "      <td>white</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>131</th>\n",
       "      <td>5.6</td>\n",
       "      <td>0.50</td>\n",
       "      <td>0.09</td>\n",
       "      <td>2.3</td>\n",
       "      <td>0.049</td>\n",
       "      <td>17.0</td>\n",
       "      <td>99.0</td>\n",
       "      <td>0.99370</td>\n",
       "      <td>3.63</td>\n",
       "      <td>0.63</td>\n",
       "      <td>13.0</td>\n",
       "      <td>5</td>\n",
       "      <td>red</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>244</th>\n",
       "      <td>15.0</td>\n",
       "      <td>0.21</td>\n",
       "      <td>0.44</td>\n",
       "      <td>2.2</td>\n",
       "      <td>0.075</td>\n",
       "      <td>10.0</td>\n",
       "      <td>24.0</td>\n",
       "      <td>1.00005</td>\n",
       "      <td>3.07</td>\n",
       "      <td>0.84</td>\n",
       "      <td>9.2</td>\n",
       "      <td>7</td>\n",
       "      <td>red</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1551</th>\n",
       "      <td>6.6</td>\n",
       "      <td>0.19</td>\n",
       "      <td>0.99</td>\n",
       "      <td>1.2</td>\n",
       "      <td>0.122</td>\n",
       "      <td>45.0</td>\n",
       "      <td>129.0</td>\n",
       "      <td>0.99360</td>\n",
       "      <td>3.09</td>\n",
       "      <td>0.31</td>\n",
       "      <td>8.7</td>\n",
       "      <td>6</td>\n",
       "      <td>white</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "      fixed acidity  volatile acidity  citric acid  residual sugar  chlorides  \\\n",
       "848             6.4              0.64         0.21             1.8      0.081   \n",
       "2529            6.6              0.42         0.13            12.8      0.044   \n",
       "131             5.6              0.50         0.09             2.3      0.049   \n",
       "244            15.0              0.21         0.44             2.2      0.075   \n",
       "1551            6.6              0.19         0.99             1.2      0.122   \n",
       "\n",
       "      free sulfur dioxide  total sulfur dioxide  density    pH  sulphates  \\\n",
       "848                  14.0                  31.0  0.99689  3.59       0.66   \n",
       "2529                 26.0                 158.0  0.99772  3.24       0.47   \n",
       "131                  17.0                  99.0  0.99370  3.63       0.63   \n",
       "244                  10.0                  24.0  1.00005  3.07       0.84   \n",
       "1551                 45.0                 129.0  0.99360  3.09       0.31   \n",
       "\n",
       "      alcohol  quality   kind  \n",
       "848       9.8        5    red  \n",
       "2529      9.0        5  white  \n",
       "131      13.0        5    red  \n",
       "244       9.2        7    red  \n",
       "1551      8.7        6  white  "
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "wine = pd.concat([white_wine.assign(kind='white'), red_wine.assign(kind='red')])\n",
    "wine.sample(5, random_state=10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Text(0, 0.5, 'quality score')"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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WdkfxjGMXwPLlSSLiBycZpRFRGoJM9tM+ELAn7v7yjiHIyKS8JQoi4iIiIhEoKUXIiIiIiIRKFEWEREREYkgJd4BlHTMMcd4ixYt4h2GiIiIiNRgK1as+MLdmxysXkIlyi1atCA7OzveYYiIiIhIDWZm/46mnpZeiIiIiIhEoERZRERERCQCJcoiIiIiIhEoURYRERERiSChLubL3/YdW299u0x52vgz4xCNiIiIiNRm1WpGOSsrizZt2tCqVSvGjx9fZv+UKVNo0qQJGRkZZGRkMHnyZADWr19P165dSU9PZ/HixQAUFhZy3nnnEQqFqrQPIiIiIlI9xGxG2cwOAxYBdYPzzHb3OyvbXlFREcOHD+f1118nLS2Nbt260bt3b0499dT96vXr14+HH354v7JJkyYxfvx4WrRowa233sqcOXOYOHEigwYNon79+pUNSURERERqsFjOKO8BznX3dCADuNDMfljZxpYtW0arVq1o2bIlderUoX///sydOzeqY1NTU8nLyyMUCpGamkpubi4vvPACgwcPrmw4IiIiIlLDxWxG2d0d+C74mBq8vLLtbdu2jWbNmhV/TktLY+nSpWXqzZkzh0WLFnHKKafwwAMP0KxZM4YPH87gwYPZs2cPkyZNYsyYMYwcORIzq2w4IiIiIlLDxXSNspklm1kO8BnwuruXyWzNbJiZZZtZ9leh3AO2Fc67yxy73+ef/exnbN68mdWrV3PeeecxZMgQAJo3b85bb73F4sWLqV+/Ptu3b6dt27YMGjSIfv368dFHH32/joqIiIhIjRPTRNndi9w9A0gDuptZhwh1Hnf3THfPbFy/4QHbSktLY8uWLcWft27dStOmTferc/TRR1O3bl0Arr32WlasWFGmnZEjRzJ27FgmTJjAgAEDGD16NKNHj65kD0VERESkpqqSu164ey7wFnBhZdvo1q0bGzZs4JNPPiE/P58ZM2bQu3fv/ers2LGjeHvevHm0a9duv/0LFy7khBNOoHXr1oRCIZKSkkhOTtadL0RERESkjFje9aIJUODuuWZWDzgP+HNl20tJSeHhhx/mggsuoKioiKFDh9K+fXtGjRpFZmYmvXv3ZsKECcybN4+UlBQaN27MlClTio93d8aNG8esWbMAGDZsGAMGDKCwsJCJEyd+v86KiIiISI1jkdb+HpKGzToBU4FkwjPXs9x9THnHdDq+rb885O9lyvXAERERERE5VMxshbtnHqxeLO96sRroHKv2RURERERiKaEeYV3nhAaaPRYRERGRhFCtHmEtIiIiIlJVlCiLiIiIiESgRFlEREREJAIlyiIiIiIiEShRFhERERGJQImyiIiIiEgESpRFRERERCJQoiwiIiIiEoESZRERERGRCJQoi4iIiIhEoERZRERERCSClHgHUNKnmzZyX79e8Q6j0n4/88V4hyAiIiIih4hmlA+x3bt30717d9LT02nfvj133nlnmTqPPfYYHTt2JCMjgx/96Ee8//77ALzzzjt06tSJbt26sXHjRgByc3O54IILcPcq7YeIiIhIbRfzRNnMks1spZnViunWunXrMn/+fFatWkVOTg5ZWVksWbJkvzpXXnkla9asIScnh5tvvpkRI0YAcN999zFnzhzuueceJk6cCMDYsWO5/fbbMbMq74uIiIhIbVYVM8o3AB9UwXkSgpnRoEEDAAoKCigoKCiT5B555JHF27t27Sren5qaSl5eHqFQiNTUVD7++GO2bdvG2WefXXUdEBEREREgxmuUzSwNuBi4GxgRy3MlkqKiIrp27crGjRsZPnw4PXr0KFPnkUce4f777yc/P5/58+cDcNtttzFs2DDq1avHtGnTuOmmmxg7dmxVhy8iIiIixH5G+UHgZmBvjM+TUJKTk8nJyWHr1q0sW7aMtWvXlqkzfPhwPv74Y/785z8zbtw4ADIyMliyZAkLFixg06ZNNG3aFHenX79+DBw4kE8//bSquyIiIiJSa8UsUTazXsBn7r7iIPWGmVm2mWXv2pMfq3DiomHDhpxzzjlkZWUdsE7//v15/vnn9ytzd8aNG8cdd9zB6NGjGT16NAMHDmTChAmxDllEREREArGcUT4D6G1mm4EZwLlm9lTpSu7+uLtnunvm4XXrxDCcqvH555+Tm5sLQF5eHm+88QZt27bdr86GDRuKt1966SVat2693/6pU6dy8cUX06hRI0KhEElJSSQlJREKhWLfAREREREBYrhG2d1vA24DMLNzgJvcfWCszpcoduzYwZAhQygqKmLv3r307duXXr16MWrUKDIzM+nduzcPP/wwb7zxBqmpqTRq1IipU6cWHx8KhZg6dSqvvfYaACNGjOCyyy6jTp06TJ8+PV7dEhEREal1rCruz1siUS73aSLNGjf0G8//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ckFBAUVF4f+5TkpKIhQKVUEvRESkNonmPsr3ldguBDYDfStwjivQsguRWuWKK67grbfe4osvviAtLY3Ro0czdOhQhg4dSocOHahTpw5Tp07FzNi+fTvXXHMNL7/8MhC+hdyAAQPIz8+nZcuWPPnkk8XtPv/883Tr1o2mTZsCcNppp9GxY0c6depEenp6XPoqIiI1l5VeI3hIGzerD2wBWrr7NwerX++ket7qrlYxi0dEYk8PHBERkURnZivcPfNg9Q46o2xmI8rb7+73l7MvBBx9sHOIiIiIiCSaaJZe7Lvrxbzg88+ARYRnig+p9ke3J3tI9qFuVkRERESkwqJJlI8Burj7twBmdhfwrLtfE8vARERERETiKZr7KDcH8kt8zgdaxCQaEREREZEEEc2M8jRgmZk9BzhwKTA1plGJiIiIiMTZQRNld7/bzF4h/FQ+gKvcfWVswxIRERERia9oZpRx9/eA9w5aUURERESkhohmjbKIiIiISK2jRFlEREREJAIlyiIiIiIiEShRFhERERGJQImyiIiIiEgESpRFRERERCKI6vZwVWb7SrjrqHhHEZ27vol3BCIiIiISQ5pR/h52795N9+7dSU9Pp3379tx5551l6uzZs4d+/frRqlUrevTowebNmwF455136NSpE926dWPjxo0A5ObmcsEFF+DuVdkNEREREYkgpomymf3OzNaZ2Vozm25mh8XyfFWtbt26zJ8/n1WrVpGTk0NWVhZLlizZr84TTzxBo0aN2LhxI7/73e+45ZZbALjvvvuYM2cO99xzDxMnTgRg7Nix3H777ZhZlfdFRERERPYXs0TZzE4Argcy3b0DkAz0j9X54sHMaNCgAQAFBQUUFBSUSXLnzp3LkCFDAOjTpw9vvvkm7k5qaip5eXmEQiFSU1P5+OOP2bZtG2effXaV90NEREREyor1GuUUoJ6ZFQD1ge0xPl+VKyoqomvXrmzcuJHhw4fTo0eP/fZv27aNZs2aAZCSksJRRx3Fl19+yW233cawYcOoV68e06ZN46abbmLs2LHx6IKIiIiIRBCzGWV33wb8Ffg/YAfwjbu/FqvzxUtycjI5OTls3bqVZcuWsXbt2v32R1pvbGZkZGSwZMkSFixYwKZNm2jatCnuTr9+/Rg4cCCffvppVXVBRERERCKI5dKLRsAlwElAU+BwMxsYod4wM8s2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\n",
      "text/plain": [
       "<Figure size 864x216 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "ax = wine.quality.value_counts().sort_index(\n",
    "    ascending=False\n",
    ").plot.barh(title='Wine Quality Scores', figsize=(12, 3))\n",
    "for bar in ax.patches:\n",
    "    ax.text(\n",
    "        bar.get_width(), \n",
    "        bar.get_y() + bar.get_height()/4, \n",
    "        f'{bar.get_width()/wine.shape[0]:.1%}'\n",
    "    )\n",
    "plt.xlabel('count of wines')\n",
    "plt.ylabel('quality score')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'pandas.core.frame.DataFrame'>\n",
      "Int64Index: 6497 entries, 0 to 1598\n",
      "Data columns (total 13 columns):\n",
      "fixed acidity           6497 non-null float64\n",
      "volatile acidity        6497 non-null float64\n",
      "citric acid             6497 non-null float64\n",
      "residual sugar          6497 non-null float64\n",
      "chlorides               6497 non-null float64\n",
      "free sulfur dioxide     6497 non-null float64\n",
      "total sulfur dioxide    6497 non-null float64\n",
      "density                 6497 non-null float64\n",
      "pH                      6497 non-null float64\n",
      "sulphates               6497 non-null float64\n",
      "alcohol                 6497 non-null float64\n",
      "quality                 6497 non-null int64\n",
      "kind                    6497 non-null object\n",
      "dtypes: float64(11), int64(1), object(1)\n",
      "memory usage: 685.2+ KB\n"
     ]
    }
   ],
   "source": [
    "wine.info()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>fixed acidity</th>\n",
       "      <th>volatile acidity</th>\n",
       "      <th>citric acid</th>\n",
       "      <th>residual sugar</th>\n",
       "      <th>chlorides</th>\n",
       "      <th>free sulfur dioxide</th>\n",
       "      <th>total sulfur dioxide</th>\n",
       "      <th>density</th>\n",
       "      <th>pH</th>\n",
       "      <th>sulphates</th>\n",
       "      <th>alcohol</th>\n",
       "      <th>quality</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>count</th>\n",
       "      <td>6497.000000</td>\n",
       "      <td>6497.000000</td>\n",
       "      <td>6497.000000</td>\n",
       "      <td>6497.000000</td>\n",
       "      <td>6497.000000</td>\n",
       "      <td>6497.000000</td>\n",
       "      <td>6497.000000</td>\n",
       "      <td>6497.000000</td>\n",
       "      <td>6497.000000</td>\n",
       "      <td>6497.000000</td>\n",
       "      <td>6497.000000</td>\n",
       "      <td>6497.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>mean</th>\n",
       "      <td>7.215307</td>\n",
       "      <td>0.339666</td>\n",
       "      <td>0.318633</td>\n",
       "      <td>5.443235</td>\n",
       "      <td>0.056034</td>\n",
       "      <td>30.525319</td>\n",
       "      <td>115.744574</td>\n",
       "      <td>0.994697</td>\n",
       "      <td>3.218501</td>\n",
       "      <td>0.531268</td>\n",
       "      <td>10.491801</td>\n",
       "      <td>5.818378</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>std</th>\n",
       "      <td>1.296434</td>\n",
       "      <td>0.164636</td>\n",
       "      <td>0.145318</td>\n",
       "      <td>4.757804</td>\n",
       "      <td>0.035034</td>\n",
       "      <td>17.749400</td>\n",
       "      <td>56.521855</td>\n",
       "      <td>0.002999</td>\n",
       "      <td>0.160787</td>\n",
       "      <td>0.148806</td>\n",
       "      <td>1.192712</td>\n",
       "      <td>0.873255</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>min</th>\n",
       "      <td>3.800000</td>\n",
       "      <td>0.080000</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.600000</td>\n",
       "      <td>0.009000</td>\n",
       "      <td>1.000000</td>\n",
       "      <td>6.000000</td>\n",
       "      <td>0.987110</td>\n",
       "      <td>2.720000</td>\n",
       "      <td>0.220000</td>\n",
       "      <td>8.000000</td>\n",
       "      <td>3.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>25%</th>\n",
       "      <td>6.400000</td>\n",
       "      <td>0.230000</td>\n",
       "      <td>0.250000</td>\n",
       "      <td>1.800000</td>\n",
       "      <td>0.038000</td>\n",
       "      <td>17.000000</td>\n",
       "      <td>77.000000</td>\n",
       "      <td>0.992340</td>\n",
       "      <td>3.110000</td>\n",
       "      <td>0.430000</td>\n",
       "      <td>9.500000</td>\n",
       "      <td>5.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>50%</th>\n",
       "      <td>7.000000</td>\n",
       "      <td>0.290000</td>\n",
       "      <td>0.310000</td>\n",
       "      <td>3.000000</td>\n",
       "      <td>0.047000</td>\n",
       "      <td>29.000000</td>\n",
       "      <td>118.000000</td>\n",
       "      <td>0.994890</td>\n",
       "      <td>3.210000</td>\n",
       "      <td>0.510000</td>\n",
       "      <td>10.300000</td>\n",
       "      <td>6.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>75%</th>\n",
       "      <td>7.700000</td>\n",
       "      <td>0.400000</td>\n",
       "      <td>0.390000</td>\n",
       "      <td>8.100000</td>\n",
       "      <td>0.065000</td>\n",
       "      <td>41.000000</td>\n",
       "      <td>156.000000</td>\n",
       "      <td>0.996990</td>\n",
       "      <td>3.320000</td>\n",
       "      <td>0.600000</td>\n",
       "      <td>11.300000</td>\n",
       "      <td>6.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>max</th>\n",
       "      <td>15.900000</td>\n",
       "      <td>1.580000</td>\n",
       "      <td>1.660000</td>\n",
       "      <td>65.800000</td>\n",
       "      <td>0.611000</td>\n",
       "      <td>289.000000</td>\n",
       "      <td>440.000000</td>\n",
       "      <td>1.038980</td>\n",
       "      <td>4.010000</td>\n",
       "      <td>2.000000</td>\n",
       "      <td>14.900000</td>\n",
       "      <td>9.000000</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "       fixed acidity  volatile acidity  citric acid  residual sugar  \\\n",
       "count    6497.000000       6497.000000  6497.000000     6497.000000   \n",
       "mean        7.215307          0.339666     0.318633        5.443235   \n",
       "std         1.296434          0.164636     0.145318        4.757804   \n",
       "min         3.800000          0.080000     0.000000        0.600000   \n",
       "25%         6.400000          0.230000     0.250000        1.800000   \n",
       "50%         7.000000          0.290000     0.310000        3.000000   \n",
       "75%         7.700000          0.400000     0.390000        8.100000   \n",
       "max        15.900000          1.580000     1.660000       65.800000   \n",
       "\n",
       "         chlorides  free sulfur dioxide  total sulfur dioxide      density  \\\n",
       "count  6497.000000          6497.000000           6497.000000  6497.000000   \n",
       "mean      0.056034            30.525319            115.744574     0.994697   \n",
       "std       0.035034            17.749400             56.521855     0.002999   \n",
       "min       0.009000             1.000000              6.000000     0.987110   \n",
       "25%       0.038000            17.000000             77.000000     0.992340   \n",
       "50%       0.047000            29.000000            118.000000     0.994890   \n",
       "75%       0.065000            41.000000            156.000000     0.996990   \n",
       "max       0.611000           289.000000            440.000000     1.038980   \n",
       "\n",
       "                pH    sulphates      alcohol      quality  \n",
       "count  6497.000000  6497.000000  6497.000000  6497.000000  \n",
       "mean      3.218501     0.531268    10.491801     5.818378  \n",
       "std       0.160787     0.148806     1.192712     0.873255  \n",
       "min       2.720000     0.220000     8.000000     3.000000  \n",
       "25%       3.110000     0.430000     9.500000     5.000000  \n",
       "50%       3.210000     0.510000    10.300000     6.000000  \n",
       "75%       3.320000     0.600000    11.300000     6.000000  \n",
       "max       4.010000     2.000000    14.900000     9.000000  "
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "wine.describe()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "white    4898\n",
       "red      1599\n",
       "Name: kind, dtype: int64"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "wine.kind.value_counts()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Train test split"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.model_selection import train_test_split\n",
    "\n",
    "wine_y = wine.pop('quality')\n",
    "wine_X = wine\n",
    "\n",
    "X_train, X_test, y_train, y_test = train_test_split(\n",
    "    wine_X, wine_y, test_size=0.25, random_state=0, stratify=wine_y\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>fixed acidity</th>\n",
       "      <th>volatile acidity</th>\n",
       "      <th>citric acid</th>\n",
       "      <th>residual sugar</th>\n",
       "      <th>chlorides</th>\n",
       "      <th>free sulfur dioxide</th>\n",
       "      <th>total sulfur dioxide</th>\n",
       "      <th>density</th>\n",
       "      <th>pH</th>\n",
       "      <th>sulphates</th>\n",
       "      <th>alcohol</th>\n",
       "      <th>kind</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>987</th>\n",
       "      <td>7.1</td>\n",
       "      <td>0.36</td>\n",
       "      <td>0.30</td>\n",
       "      <td>1.6</td>\n",
       "      <td>0.080</td>\n",
       "      <td>35.0</td>\n",
       "      <td>70.0</td>\n",
       "      <td>0.99693</td>\n",
       "      <td>3.44</td>\n",
       "      <td>0.50</td>\n",
       "      <td>9.4</td>\n",
       "      <td>red</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1219</th>\n",
       "      <td>8.2</td>\n",
       "      <td>0.37</td>\n",
       "      <td>0.36</td>\n",
       "      <td>1.0</td>\n",
       "      <td>0.034</td>\n",
       "      <td>17.0</td>\n",
       "      <td>93.0</td>\n",
       "      <td>0.99060</td>\n",
       "      <td>3.04</td>\n",
       "      <td>0.32</td>\n",
       "      <td>11.7</td>\n",
       "      <td>white</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2380</th>\n",
       "      <td>6.4</td>\n",
       "      <td>0.27</td>\n",
       "      <td>0.19</td>\n",
       "      <td>1.9</td>\n",
       "      <td>0.085</td>\n",
       "      <td>21.0</td>\n",
       "      <td>196.0</td>\n",
       "      <td>0.99516</td>\n",
       "      <td>3.49</td>\n",
       "      <td>0.64</td>\n",
       "      <td>9.5</td>\n",
       "      <td>white</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2770</th>\n",
       "      <td>6.4</td>\n",
       "      <td>0.44</td>\n",
       "      <td>0.44</td>\n",
       "      <td>14.4</td>\n",
       "      <td>0.048</td>\n",
       "      <td>29.0</td>\n",
       "      <td>228.0</td>\n",
       "      <td>0.99955</td>\n",
       "      <td>3.26</td>\n",
       "      <td>0.54</td>\n",
       "      <td>8.8</td>\n",
       "      <td>white</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>857</th>\n",
       "      <td>8.2</td>\n",
       "      <td>0.40</td>\n",
       "      <td>0.48</td>\n",
       "      <td>13.7</td>\n",
       "      <td>0.042</td>\n",
       "      <td>59.0</td>\n",
       "      <td>169.0</td>\n",
       "      <td>0.99860</td>\n",
       "      <td>3.10</td>\n",
       "      <td>0.52</td>\n",
       "      <td>9.4</td>\n",
       "      <td>white</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "      fixed acidity  volatile acidity  citric acid  residual sugar  chlorides  \\\n",
       "987             7.1              0.36         0.30             1.6      0.080   \n",
       "1219            8.2              0.37         0.36             1.0      0.034   \n",
       "2380            6.4              0.27         0.19             1.9      0.085   \n",
       "2770            6.4              0.44         0.44            14.4      0.048   \n",
       "857             8.2              0.40         0.48            13.7      0.042   \n",
       "\n",
       "      free sulfur dioxide  total sulfur dioxide  density    pH  sulphates  \\\n",
       "987                  35.0                  70.0  0.99693  3.44       0.50   \n",
       "1219                 17.0                  93.0  0.99060  3.04       0.32   \n",
       "2380                 21.0                 196.0  0.99516  3.49       0.64   \n",
       "2770                 29.0                 228.0  0.99955  3.26       0.54   \n",
       "857                  59.0                 169.0  0.99860  3.10       0.52   \n",
       "\n",
       "      alcohol   kind  \n",
       "987       9.4    red  \n",
       "1219     11.7  white  \n",
       "2380      9.5  white  \n",
       "2770      8.8  white  \n",
       "857       9.4  white  "
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X_train.sample(5, random_state=0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Build models\n",
    "### Random Forest"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%capture\n",
    "from sklearn.compose import ColumnTransformer\n",
    "from sklearn.ensemble import RandomForestClassifier\n",
    "from sklearn.model_selection import GridSearchCV\n",
    "from sklearn.pipeline import Pipeline\n",
    "from sklearn.preprocessing import StandardScaler, OneHotEncoder\n",
    "\n",
    "pipeline = Pipeline([\n",
    "    ('transformer', ColumnTransformer([\n",
    "        ('scale', StandardScaler(), slice(0, -1)),\n",
    "        ('encode', OneHotEncoder(sparse=False), [-1])\n",
    "    ])),\n",
    "    ('rf', RandomForestClassifier(n_estimators=100, random_state=0))\n",
    "])\n",
    "\n",
    "search_space = {\n",
    "    'rf__max_depth' : np.arange(5, 20, 5)\n",
    "}\n",
    "\n",
    "rf = GridSearchCV(pipeline, search_space, scoring='f1_macro', cv=5).fit(X_train, y_train)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Gradient Boosted Trees"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%capture\n",
    "from sklearn.compose import ColumnTransformer\n",
    "from sklearn.ensemble import GradientBoostingClassifier\n",
    "from sklearn.model_selection import GridSearchCV\n",
    "from sklearn.pipeline import Pipeline\n",
    "from sklearn.preprocessing import StandardScaler, OneHotEncoder\n",
    "\n",
    "pipeline = Pipeline([\n",
    "    ('transformer', ColumnTransformer([\n",
    "        ('scale', StandardScaler(), slice(0, -1)),\n",
    "        ('encode', OneHotEncoder(sparse=False), [-1])\n",
    "    ])),\n",
    "    ('gb', GradientBoostingClassifier(random_state=0))\n",
    "])\n",
    "\n",
    "search_space = {\n",
    "    'gb__max_depth' : np.arange(3, 12, 3)\n",
    "}\n",
    "\n",
    "gb = GridSearchCV(pipeline, search_space, scoring='f1_macro', cv=5).fit(X_train, y_train)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### KNN"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%capture\n",
    "from sklearn.compose import ColumnTransformer\n",
    "from sklearn.model_selection import GridSearchCV\n",
    "from sklearn.neighbors import KNeighborsClassifier\n",
    "from sklearn.pipeline import Pipeline\n",
    "from sklearn.preprocessing import StandardScaler, OneHotEncoder\n",
    "\n",
    "pipeline = Pipeline([\n",
    "    ('transformer', ColumnTransformer([\n",
    "        ('scale', StandardScaler(), slice(0, -1)),\n",
    "        ('encode', OneHotEncoder(sparse=False), [-1])\n",
    "    ])),\n",
    "    ('knn', KNeighborsClassifier())\n",
    "])\n",
    "\n",
    "search_space = {\n",
    "    'knn__n_neighbors' : np.arange(1, 5)\n",
    "}\n",
    "\n",
    "knn = GridSearchCV(pipeline, search_space, scoring='f1_macro', cv=5).fit(X_train, y_train)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Logistic Regression"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%capture\n",
    "from sklearn.compose import ColumnTransformer\n",
    "from sklearn.linear_model import LogisticRegression\n",
    "from sklearn.model_selection import GridSearchCV\n",
    "from sklearn.pipeline import Pipeline\n",
    "from sklearn.preprocessing import StandardScaler, OneHotEncoder\n",
    "\n",
    "pipeline = Pipeline([\n",
    "    ('transformer', ColumnTransformer([\n",
    "        ('scale', StandardScaler(), slice(0, -1)),\n",
    "        ('encode', OneHotEncoder(sparse=False), [-1])\n",
    "    ])),\n",
    "    ('lr', LogisticRegression(solver='lbfgs', random_state=0, multi_class='multinomial'))\n",
    "])\n",
    "\n",
    "search_space = {\n",
    "    'lr__C' : [0.1, 0.5, 1, 5]\n",
    "}\n",
    "\n",
    "lr = GridSearchCV(pipeline, search_space, scoring='f1_macro', cv=5).fit(X_train, y_train)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Naive Bayes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%capture\n",
    "from sklearn.compose import ColumnTransformer\n",
    "from sklearn.model_selection import GridSearchCV\n",
    "from sklearn.naive_bayes import GaussianNB\n",
    "from sklearn.pipeline import Pipeline\n",
    "from sklearn.preprocessing import StandardScaler, OneHotEncoder\n",
    "\n",
    "nb = Pipeline([\n",
    "    ('transformer', ColumnTransformer([\n",
    "        ('scale', StandardScaler(), slice(0, -1)),\n",
    "        ('encode', OneHotEncoder(sparse=False), [-1])\n",
    "    ])),\n",
    "    ('nb', GaussianNB())\n",
    "]).fit(X_train, y_train)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Determine agreement between the models with Cohen's Kappa"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Cohen's Kappa between random forest and gradient boosting is: 78.97%\n",
      "Cohen's Kappa between random forest and knn is: 55.49%\n",
      "Cohen's Kappa between random forest and logistic regression is: 51.43%\n",
      "Cohen's Kappa between random forest and naive bayes is: 13.25%\n",
      "Cohen's Kappa between gradient boosting and knn is: 57.10%\n",
      "Cohen's Kappa between gradient boosting and logistic regression is: 42.14%\n",
      "Cohen's Kappa between gradient boosting and naive bayes is: 12.61%\n",
      "Cohen's Kappa between knn and logistic regression is: 24.77%\n",
      "Cohen's Kappa between knn and naive bayes is: 8.89%\n",
      "Cohen's Kappa between logistic regression and naive bayes is: 19.61%\n"
     ]
    }
   ],
   "source": [
    "import itertools\n",
    "from sklearn.metrics import cohen_kappa_score\n",
    "\n",
    "models = zip(\n",
    "    ['random forest', 'gradient boosting', 'knn', 'logistic regression', 'naive bayes'], \n",
    "    [rf, gb, knn, lr, nb]\n",
    ")\n",
    "\n",
    "def get_preds(model, test_X_data):\n",
    "    return model.predict(test_X_data)\n",
    "\n",
    "for ((model_1_name, model_1), (model_2_name, model_2)) in itertools.combinations(models, 2):\n",
    "    score = cohen_kappa_score(*map(get_preds, [model_1, model_2], itertools.repeat(X_test)))\n",
    "    print(f\"Cohen's Kappa between {model_1_name} and {model_2_name} is: {score:.2%}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Voting Classifier with Majority Rules"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%capture\n",
    "from sklearn.ensemble import VotingClassifier\n",
    "\n",
    "majority_rules = VotingClassifier(\n",
    "    [('rf', rf.best_estimator_), ('gb', gb.best_estimator_), \n",
    "     ('knn', knn.best_estimator_), ('lr', lr.best_estimator_),\n",
    "     ('nb', nb)],\n",
    "    voting='hard',\n",
    "    weights=[1, 1, 1, 1, .5]\n",
    ").fit(X_train, y_train)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Evaluate model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.672"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "majority_rules.score(X_test, y_test)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [],
   "source": [
    "preds = majority_rules.predict(X_test)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "              precision    recall  f1-score   support\n",
      "\n",
      "           3       0.00      0.00      0.00         8\n",
      "           4       0.88      0.13      0.23        54\n",
      "           5       0.70      0.71      0.71       535\n",
      "           6       0.63      0.78      0.70       709\n",
      "           7       0.73      0.49      0.59       270\n",
      "           8       0.89      0.35      0.51        48\n",
      "           9       0.00      0.00      0.00         1\n",
      "\n",
      "   micro avg       0.67      0.67      0.67      1625\n",
      "   macro avg       0.55      0.35      0.39      1625\n",
      "weighted avg       0.69      0.67      0.66      1625\n",
      "\n"
     ]
    }
   ],
   "source": [
    "%%capture --no-stdout\n",
    "from sklearn.metrics import classification_report\n",
    "print(classification_report(y_test, preds))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.axes._subplots.AxesSubplot at 0x140bb10>"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "from ml_utils.classification import confusion_matrix_visual\n",
    "\n",
    "confusion_matrix_visual(y_test, preds, np.sort(wine_y.unique()))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
